{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "initial_id",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-10-10T04:01:00.331954Z",
     "start_time": "2025-10-10T04:00:48.139690Z"
    }
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "D:\\JNU\\Project\\Python\\2025FMa\\.venv\\Lib\\site-packages\\tqdm\\auto.py:21: TqdmWarning: IProgress not found. Please update jupyter and ipywidgets. See https://ipywidgets.readthedocs.io/en/stable/user_install.html\n",
      "  from .autonotebook import tqdm as notebook_tqdm\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "WARNING:tensorflow:From D:\\JNU\\Project\\Python\\2025FMa\\.venv\\Lib\\site-packages\\tf_keras\\src\\losses.py:2976: The name tf.losses.sparse_softmax_cross_entropy is deprecated. Please use tf.compat.v1.losses.sparse_softmax_cross_entropy instead.\n",
      "\n"
     ]
    }
   ],
   "source": [
    "from transformers import (\n",
    "    AutoTokenizer,\n",
    "    DataCollatorWithPadding,\n",
    "    AutoModelForSequenceClassification,\n",
    "    TrainingArguments,\n",
    "    Trainer,\n",
    ")\n",
    "from sklearn.metrics import (\n",
    "    accuracy_score,\n",
    "    precision_recall_fscore_support,\n",
    ")\n",
    "import datasets"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "49a3d1ed05a334fe",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-10-08T07:41:10.194456Z",
     "start_time": "2025-10-08T07:41:07.598592Z"
    }
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "Generating train split: 45013 examples [00:00, 393407.46 examples/s]\n",
      "Generating test split: 4988 examples [00:00, 293420.69 examples/s]\n",
      "Some weights of BertForSequenceClassification were not initialized from the model checkpoint at bert-base-chinese and are newly initialized: ['classifier.bias', 'classifier.weight']\n",
      "You should probably TRAIN this model on a down-stream task to be able to use it for predictions and inference.\n",
      "Map: 100%|██████████| 45013/45013 [00:07<00:00, 5712.64 examples/s]\n",
      "Map: 100%|██████████| 4988/4988 [00:01<00:00, 3954.49 examples/s]"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "DatasetDict({\n",
      "    train: Dataset({\n",
      "        features: ['SentimentText', 'label', 'input_ids', 'token_type_ids', 'attention_mask'],\n",
      "        num_rows: 45013\n",
      "    })\n",
      "    test: Dataset({\n",
      "        features: ['SentimentText', 'label', 'input_ids', 'token_type_ids', 'attention_mask'],\n",
      "        num_rows: 4988\n",
      "    })\n",
      "})\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\n"
     ]
    }
   ],
   "source": [
    "# data_path = {'train': './data/reviews.csv', 'test': './data/reviews.csv'}\n",
    "full_fine_tuning = False\n",
    "data_path = {'train': './data/train.csv', 'test': './data/dev.csv'}\n",
    "raw_datasets = datasets.load_dataset('csv', data_files=data_path, delimiter=',')\n",
    "model_name_for_path = 'bert-base-chinese'\n",
    "tokenizer = AutoTokenizer.from_pretrained(model_name_for_path)\n",
    "model = AutoModelForSequenceClassification.from_pretrained(model_name_for_path, num_labels=2)\n",
    "\n",
    "def tokenize_function(examples):\n",
    "    return tokenizer(examples['SentimentText'], padding=\"max_length\", truncation=True)\n",
    "\n",
    "\n",
    "tokenized_datasets = raw_datasets.map(tokenize_function, batched=True)\n",
    "data_collator = DataCollatorWithPadding(tokenizer=tokenizer)\n",
    "print(tokenized_datasets)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "58c59c6283970c95",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-10-08T07:41:24.038196Z",
     "start_time": "2025-10-08T07:41:23.695801Z"
    }
   },
   "outputs": [],
   "source": [
    "train_dataset = tokenized_datasets['train'].shuffle(seed=114514)\n",
    "eval_dataset = tokenized_datasets['test'].shuffle(seed=114514)\n",
    "\n",
    "\n",
    "def compute_metrics(pred):\n",
    "    labels = pred.label_ids\n",
    "    preds = pred.predictions.argmax(-1)\n",
    "    precision, recall, f1, _ = precision_recall_fscore_support(labels, preds, average='weighted')\n",
    "    acc = accuracy_score(labels, preds)\n",
    "    return {\n",
    "        'accuracy': acc,\n",
    "        'f1': f1,\n",
    "        'precision': precision,\n",
    "        'recall': recall,\n",
    "    }\n",
    "\n",
    "training_args = TrainingArguments(\n",
    "    output_dir='./review_trainer',\n",
    "    eval_strategy='epoch',\n",
    "    per_device_train_batch_size=32,\n",
    "    per_device_eval_batch_size=32,\n",
    "    learning_rate=5e-5,\n",
    "    num_train_epochs=3,\n",
    "    warmup_ratio=0.2,\n",
    "    logging_dir='./review_train_logs',\n",
    "    logging_strategy='epoch',\n",
    "    save_strategy='epoch',\n",
    "    report_to='tensorboard',\n",
    ")\n",
    "trainer = Trainer(\n",
    "    model=model,\n",
    "    args=training_args,\n",
    "    train_dataset=tokenized_datasets['train'],\n",
    "    eval_dataset=tokenized_datasets['test'],\n",
    "    data_collator=data_collator,\n",
    "    processing_class=tokenizer,\n",
    "    compute_metrics=compute_metrics,\n",
    ")\n",
    "\n",
    "if not full_fine_tuning:\n",
    "    for param in model.bert.parameters():\n",
    "        param.requires_grad = False"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "4875e523de8dc1fe",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-10-08T07:41:41.634705Z",
     "start_time": "2025-10-08T07:41:28.967871Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/html": [
       "\n",
       "    <div>\n",
       "      \n",
       "      <progress value='4221' max='4221' style='width:300px; height:20px; vertical-align: middle;'></progress>\n",
       "      [4221/4221 26:28, Epoch 3/3]\n",
       "    </div>\n",
       "    <table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       " <tr style=\"text-align: left;\">\n",
       "      <th>Epoch</th>\n",
       "      <th>Training Loss</th>\n",
       "      <th>Validation Loss</th>\n",
       "      <th>Accuracy</th>\n",
       "      <th>F1</th>\n",
       "      <th>Precision</th>\n",
       "      <th>Recall</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <td>1</td>\n",
       "      <td>0.596300</td>\n",
       "      <td>0.431341</td>\n",
       "      <td>0.845630</td>\n",
       "      <td>0.845633</td>\n",
       "      <td>0.845639</td>\n",
       "      <td>0.845630</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>2</td>\n",
       "      <td>0.428900</td>\n",
       "      <td>0.375993</td>\n",
       "      <td>0.855654</td>\n",
       "      <td>0.855651</td>\n",
       "      <td>0.856481</td>\n",
       "      <td>0.855654</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>3</td>\n",
       "      <td>0.401200</td>\n",
       "      <td>0.363837</td>\n",
       "      <td>0.860465</td>\n",
       "      <td>0.860478</td>\n",
       "      <td>0.860563</td>\n",
       "      <td>0.860465</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table><p>"
      ],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "trainer.train()\n",
    "model_path = './review_model' if full_fine_tuning else './review_classifier_model'\n",
    "trainer.save_model(model_path)"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.11.8"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
